//== SAGITTARIUS ============================================================================

//== BEGINNING OF CODE ===============================================================

#ifndef __SAGITTARIUS__GMPSUPPORT__H_
#define __SAGITTARIUS__GMPSUPPORT__H_

//== INCLUDES ========================================================================

#include "sagittarius/core/SagittariusCore.h"

#include <stdio.h>
#include <gmp.h>


#ifdef __cplusplus
extern "C" {
#endif

//TODO: remove the bignum_t wrapper to mpz_t. It does nothing useful
//(accept perhaps for the SG_DECLARE_BIGNUM define).
typedef struct {
    mpz_t v;
    int flg; //intialization flag
} bignum_t;

///Future-proof way to get the value of a bignum (because I'm thinking of typedef'ing bignum_t to mpz_t)
#define SG_BIGNUM_GETMPZ(x) (x).v

#define SG_DECLARE_BIGNUM(name) bignum_t name={.flg=0}
#define SG_GET_BIGNUM_UI(x) mpz_get_ui((x).v)
#define SG_BIGNUM_CMP(x, y) mpz_cmp((x).v, (y).v)
#define SG_BIGNUM_CMP_UI(x, y) mpz_cmp_ui((x).v, y)

//initializes if necessary
void sg_bignum_set(bignum_t* r, bignum_t* x);
void sg_bignum_set_ui(bignum_t* r, unsigned long x);

bignum_t sg_make_bignum(unsigned long x);

void sg_bignum_clear(bignum_t* r);

bignum_t* sg_bignum_create_buf(size_t len);
//calls mpz_clear for each element
//void sg_bignum_clearbuf(bignum_t* buf, size_t len);
//same as above but also frees memory allocated for the buffer
void sg_bignum_deletebuf(bignum_t* buf, size_t len);

//replacement for memcpy
//assumes dest is not initialized
//DANGER: n is the number of bignum_t's in the block, not the number of bytes as with memcpy
//Also, there is no return value
void gmpcopy(bignum_t* dest, bignum_t* src, size_t n);

//overwrites contents of dest with ui val x, assuming that dest has been initialized
//void gmpmemoverwrite_ui(bignum_t* dest, unsigned long x, size_t n);
void gmpmemset_ui(bignum_t* dest, unsigned long x, size_t n);

void sg_bignum_print(bignum_t a);

void sg_bignum_lshift(bignum_t* r, bignum_t a);
void sg_bignum_lshift_ui(bignum_t* r, unsigned long x);
void sg_bignum_rshift(bignum_t* r, bignum_t a);
void sg_bignum_rshift_ui(bignum_t* r, unsigned long x);

#ifdef __cplusplus
}//extern "C"
#endif

#endif
